package com.mfz.common.dbHelper

import org.apache.logging.log4j.LogManager
import java.util.*

internal val logPool = LogManager.getLogger(ConnectionPool::class.java.name)!!
typealias CreateHelper = (Helper?, ConnectionPool) -> Helper


/**
 * 连接池对象.
 * 根据数据库配置文件，每个连接应用一个此对象。
 */
class ConnectionPool(private var timedOut: Long, private val poolNumber: Int, createHelper: CreateHelper) {
	internal val lock = Object()

	private var helper: Helper = createHelper(null, this)
	private val threadHelpers: Hashtable<Thread, Helper> = Hashtable(poolNumber * 3 / 4 + 1)

	val format: (value: Any?) -> String = this.helper::format

	@Suppress("unused")
	val size: Int
		get() = poolNumber

	init {
		if (poolNumber < 1) {
			throw IndexOutOfBoundsException("连接池内连接数量必须大于等于1")
		}
		timedOut *= 1000 //将超时时间修改成毫秒


		val first = this.helper
		for (i in 1 until poolNumber) {
			this.helper = createHelper(helper, this)
		}

		if (first is AbstractJDBCHelper)
			first.next = this.helper
	}

	fun getFreeHelper(isInThread: Boolean = false): Helper {
		val temp = helper
		while (true) {
			synchronized(lock) {
				do {
					if (helper is AbstractJDBCHelper)
						helper = (helper as AbstractJDBCHelper).next ?: error("这里完全不应该出现")

					if (!helper.isInUse) {
						handleIdleReplaceConnection(helper)
						helper.use(isInThread)
//						log.trace("得到一个连接，$helper")
						return helper
					}
				} while (temp != helper)

				logPool.error("所有连接都忙。等待释放连接中！")
				lock.wait()
			}
		}
	}

	/**
	 * 获得一个连接。并将此连接与当前线程对接上。
	 *
	 * 如果当前线程已经对应过连接，直接返回当前线程对应的连接。
	 *
	 */
	fun getThreadHelper(): Helper {
		val t = Thread.currentThread()
		if (!threadHelpers.containsKey(t)) {
			threadHelpers[t] = getFreeHelper(true)
		}
		return threadHelpers[t] ?: error("这里应该一定有值的")
	}

	fun contains(): Boolean {
		return threadHelpers.containsKey(Thread.currentThread())
	}

	/**
	 * 清除掉线程对应关系
	 */
	internal fun clearThreadHelper(t: Thread) {
		threadHelpers.remove(t)
	}

	private fun handleIdleReplaceConnection(helper: Helper) {
		//进行一个保护，如果有其他的数据处理对象，可以在这里继续
		if (helper is AbstractJDBCHelper) {
			//如果连接空闲时间超过指定时间，重新连接
			if (helper.lastUseTime + timedOut < System.currentTimeMillis()) {
				logPool.debug("超时,更新数据库连接。上次使用时间:${helper.lastUseTime},超时时间:$timedOut,当前系统时间:${System.currentTimeMillis()}")
				helper.renewConnection()
			}
		}
	}

	fun close() {
		log.trace("连接池开始进行关闭。")

		val temp = helper
		var h = temp
		do {
			h = (h as AbstractJDBCHelper).next ?: error("这里完全不应该出现")
			h.close(true, closeThread = true)
		} while (temp != helper)
	}
}

